unit SceneGUI;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, AsphyreFonts, Asphyre2D, AsphyreCanvas, AsphyreSubsc,
 AsphyreDevices, AsphyreImages, AsphyreDb, AsphyreTimers, AsphyreTextures,
  AsphyreMouse, AsphyreDef, AsphyreKeyboard, DirectInput, GUIEdit;

type

TSceneGui = class
private
  Images: TAsphyreImages;
  Canvas: TAsphyreCanvas;
  Fonts: TAsphyreFonts;
  Keyboard: TAsphyreKeyboard;
  Mouses: TAsphyreMouse;
  FControls:array of TSceneGUI;
  function GetControlsCount:integer;
  function GetControl(Index:integer):TSceneGui;
  function TextLines(Text:string;x,y,scale:real;number,Color1,Color2,
      widthL:integer;Effect:integer; screentop:real=0;
      screenbottom:real=768; yspace:integer=0):integer;
  procedure SetControl(Index:integer; const Value:TSceneGUI);
public
  Wait:integer;
  MouseIsIn:boolean;
  Pressed:boolean;
  Parent:TSceneGUI;
  SomeData:string;
  Enabled:boolean;
  Visible:boolean;
  Top,Left,Height,Width:integer;
  FontNumb:byte;
  FontScale:double;
  Caption:string;
  EnabledColor:TColor4;
  DisabledColor:TColor4;
  HighlightedColor:TColor4;
  PushedColor:TColor4;
  LineColor:TColor4;
  RenderFX:cardinal;
  FontEnabledColor:TColor4;
  FontDisabledColor:TColor4;
  FontHighlightedColor:TColor4;
  FontPushedColor:TColor4;
  FontRenderFX:cardinal;
  OnClick:TNotifyEvent;
  OnEnter:TNotifyEvent;
  OnExit:TNotifyEvent;
  procedure AddControl(Control:TSceneGUI);
  procedure DeleteControl(Number:integer);
  procedure Move; virtual;
  procedure Render; virtual;
  property Controls[Index:integer]:TSceneGUI read GetControl write SetControl;
  property ControlsCount:integer read GetControlsCount;
  constructor Create(AImages: TAsphyreImages;
    ACanvas: TAsphyreCanvas; AFonts: TAsphyreFonts; AKeyboard: TAsphyreKeyboard;
    AMouses: TAsphyreMouse; Bounds:TRect); virtual;
  destructor Destroy; override;
end;

TSceneGUIEdit = class (TSceneGui)
private
  Position:integer;
  Selected:boolean;
public
  procedure Move; override;
  procedure Render; override;
end;

TSceneGUIMultiEdit = class (TSceneGUIEdit)
private
  ScrollY:integer;
  AllHeight:real;
public
  procedure Move; override;
  procedure Render; override;
end;


TSceneGUIList = class (TSceneGui)
private
public
  Strings:TStringList;
  SelectedNumb:integer;
  RolledoverNumb:integer;
  PushedNumb:integer;
  ScrollY:integer;
  procedure Move; override;
  procedure Render; override;
  constructor Create(AImages: TAsphyreImages; ACanvas: TAsphyreCanvas;
    AFonts: TAsphyreFonts; AKeyboard: TAsphyreKeyboard; AMouses: TAsphyreMouse;
    Bounds:TRect); override;
end;

implementation

uses Types, Math;

const
 TextChars = [#$30..#$5A];

constructor TSceneGui.Create(AImages: TAsphyreImages; ACanvas: TAsphyreCanvas;
  AFonts: TAsphyreFonts; AKeyboard: TAsphyreKeyboard; AMouses: TAsphyreMouse;
  Bounds:TRect);
begin
  inherited Create;
  Canvas:=ACanvas;
  Fonts:=AFonts;
  Keyboard:=AKeyboard;
  Images:=AImages;
  Mouses:=AMouses;
  Top:=Bounds.Top;
  Left:=Bounds.Left;
  Height:=Bounds.Bottom-Bounds.Top;
  Width:=Bounds.Right-Bounds.Left;
  EnabledColor:=clWhite4;
  DisabledColor:=clGray4;
  HighlightedColor:=clYellow4;
  PushedColor:=clRed4;
  LineColor:=clBlack4;
  FontEnabledColor:=clWhite4;
  FontDisabledColor:=clGray4;
  FontHighlightedColor:=clYellow4;
  FontPushedColor:=clWhite4;
  FontNumb:=0;
  FontScale:=1;
  Visible:=true;
  Enabled:=true;
  RenderFX:=fxBlend;
  FontRenderFX:=fxBlend;
end;

function TSceneGui.TextLines(Text:string;x,y,scale:real;number,Color1,Color2,
      widthL:integer;Effect:integer; screentop:real=0;
      screenbottom:real=768; yspace:integer=0):integer;
var
  d: integer;
  Str,s1: string;
  oldscale: real;
begin
  D:=0;
  str:='';
  oldscale:=Fonts[number].Scale;
  Fonts[number].Scale:=scale;
  repeat
    if Pos(' ',text)>0 then
    s1:=Copy(text,1,Pos(' ',text))
    else
    s1:=text;
    Delete(text,1,Length(s1));
    if (Fonts.items[number].TextWidth(Str+s1)>widthL)or
      ((text<>'') and (text[1]=#13)) then
    begin
      if ((y+(d+1)*(Fonts.items[number].TextHeight(Str)+yspace))>
        screentop)and((y+d*(Fonts.items[number].TextHeight(Str)+yspace))<
        screenbottom) then
      Fonts.items[number].TextOut(Str,x,y+d*
        (Fonts.items[number].TextHeight(Str)+yspace)
        ,Color1,Color2,effect);
      inc(d);
      str:='';
    end;
    Str:=str+s1;
  until text='';
  if ((y+(d+1)*(Fonts.items[number].TextHeight(Str)+yspace)
    )>=screentop)and((y+d*(Fonts.items[number].TextHeight(Str)+yspace))<=
    screenbottom) then
  Fonts.items[number].TextOut(Str,x,y+d*(Fonts.items[number].TextHeight(Str)+
    yspace),Color1,color2,effect);
  result:=round(y+(d+1)*(Fonts.items[number].TextHeight(Str)+yspace));
  Fonts[number].Scale:=oldscale;
end;


destructor TSceneGui.Destroy;
var
i:integer;
begin
  for i := 0 to ControlsCount-1 do
  Controls[i].Free;
  inherited;
end;

function TSceneGui.GetControl(Index:integer):TSceneGui;
begin
  Result:=FControls[Index];
end;

function TSceneGui.GetControlsCount:integer;
begin
  Result:=length(FControls);
end;

procedure TSceneGui.SetControl(Index:integer; const Value:TSceneGUI);
begin
  FControls[Index].Free;
  FControls[Index]:=Value;
end;

procedure TSceneGui.AddControl(Control:TSceneGUI);
var
temp:integer;
begin
  temp:=Length(FControls);
  SetLength(FControls,temp+1);
  FControls[temp]:=Control;
  FControls[temp].Parent:=self;
end;

procedure TSceneGui.DeleteControl(Number:integer);
var
temp,i:integer;
TempControl:TSceneGui;
begin
  temp:=Length(FControls);
  TempControl:=FControls[Number];
  for i := number to temp-2 do
  FControls[i]:=FControls[i+1];
  SetLength(FControls,temp-1);
  TempControl.Free;
end;

procedure TSceneGui.Move;
var
i:integer;
begin
  if not Visible then
  exit;
  inc(Wait);
  if PtInRect(Bounds(Left,Top,Width,Height),Mouse.CursorPos) then
  begin
    if not MouseIsIn and Enabled then
    if Assigned(OnEnter) then
    OnEnter(self);
    MouseIsIn:=true;
    if Mouses.Pressed[0] then
    Pressed:=true
    else
    begin
      if Pressed then
      begin
        if Enabled then
        if Assigned(OnClick) then
        OnClick(self);
        Pressed:=false;
      end;
    end;
  end
  else
  begin
    if MouseIsIn and Enabled then
    if Assigned(OnExit) then
    OnExit(self);
    MouseIsIn:=false;
    Pressed:=false;
  end;
  if Visible then
  for i := 0 to ControlsCount-1 do
  FControls[i].Move;
end;

procedure TSceneGui.Render;
var
rescliprect:TRect;
i:integer;
ExSize:real;
begin
  if not Visible then
  exit;
  rescliprect:=Canvas.ClipRect;
  Canvas.ClipRect:=Bounds(Left,Top,Width,Height);

  ExSize:=Fonts[FontNumb].Scale;
  Fonts[FontNumb].Scale:=FontScale;
  if not Enabled then
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,DisabledColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontDisabledColor[0],
      FontDisabledColor[1], FontRenderFX);
  end
  else
  if Pressed then
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,PushedColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontPushedColor[0],
      FontPushedColor[1], FontRenderFX);
  end
  else
  if MouseIsIn then
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,HighlightedColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontHighlightedColor[0],
      FontHighlightedColor[1], FontRenderFX);
  end
  else
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,EnabledColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontEnabledColor[0],
      FontEnabledColor[1], FontRenderFX);
  end;
  Fonts[FontNumb].Scale:=ExSize;
  if Visible then
  for i := 0 to ControlsCount-1 do
  FControls[i].Render;
  Canvas.ClipRect:=rescliprect;
end;


procedure TSceneGUIEdit.Move;
var
Ch:char;
i:integer;
begin
  if PtInRect(Bounds(Left,Top,Width,Height),Mouse.CursorPos) then
  if not Mouses.Pressed[0] then
  if Pressed then 
  begin
    Selected:=true;
    Position:=Length(Caption);
  end;
  inherited;
  if Selected then
  begin
    if Keyboard.KeyPressed[DIK_Left] then
    begin
      dec(Position);
      Position:=Max(0,Position);
    end;
    if Keyboard.KeyPressed[DIK_RIGHT] then
    begin
      inc(Position);
      Position:=Min(length(Caption),Position);
    end;
    if Keyboard.KeyPressed[DIK_Delete] then
    begin
      Delete(Caption,Position+1,1);
    end;
    for i := 0 to 255 do
    if Keyboard.VKeyPressed[i] then
    begin
      if i = VK_Back then
      begin
        Delete(Caption,Position,1);
        dec(Position);
        Position:=Max(0,Position);
        continue;
      end;
      if i = VK_SPACE then
      begin
        Insert(' ',Caption,Position+1);
        inc(Position);
        continue;
      end;
      if i = VK_RETURN then
      begin
        Insert(#13#10,Caption,Position+1);
        inc(Position,2);
        continue;
      end;
      Ch:= Char(i);
      if (Ch in TextChars) then
      begin
        if Keyboard.Key[DIK_LSHIFT] then
        Insert(UpperCase(Ch),Caption,Position+1)
        else
        Insert(LowerCase(Ch),Caption,Position+1);
        inc(Position);
      end;
    end;
  end;
end;

procedure TSceneGuiEdit.Render;
var
letterwidth,letterheight,spacedwidth:real;
begin
  inherited;
  if Caption='' then
  exit;
  if not Selected then
  exit;
  letterwidth:=Fonts[FontNumb].TextWidth(Caption[Position+1])*FontScale;
  letterheight:=Fonts[FontNumb].TextHeight(Caption)*FontScale;
  spacedwidth:=Fonts[FontNumb].TextWidth(Copy(Caption,1,Position))*FontScale;
  Canvas.Rectangle(
    round(left+width/2-Fonts[FontNumb].TextWidth(Caption)*FontScale/2+
    spacedwidth),round(Top+Height/2-letterheight/2),
    round(letterwidth),round(letterheight),LineColor,HighlightedColor,RenderFX);
end;

procedure TSceneGUIList.Move;
var
letterheight:real;
i:integer;
begin
  letterheight:=Fonts[FontNumb].TextHeight('1')*FontScale;
  RolledoverNumb:=-1;
  if Pressed and not Mouses.Pressed[0] then
  SelectedNumb:=-1;
  if MouseIsIn then
  for i := 0 to Strings.Count-1 do
  if PtInRect(Bounds(Left+5,round(-ScrollY+Top+5+i*(5+letterheight)),Width-10,
      round(letterheight+1)),Mouse.CursorPos) then
  begin
    if Pressed then
    begin
      if Mouses.Pressed[0] then
      PushedNumb:=i
      else
      SelectedNumb:=i;
    end
    else
    RolledoverNumb:=i;
    break;
  end;
  if Mouses.Pressed[0] then
  begin
    if  Strings.Count*(5+letterheight)>Height then
    if PtInRect(Bounds(Left+Width+1,Top,14,Height),Mouse.CursorPos) then
    begin
      ScrollY:=round((Mouse.CursorPos.Y-Top-
        round(Height*Height/(5+Strings.Count*(5+letterheight))-2)/2)/Height*(5+
        Strings.Count*(5+letterheight)));
      ScrollY:=Max(ScrollY,0);
      ScrollY:=Min(ScrollY,round((5+Strings.Count*(5+
        letterheight))-Height));
    end;
  end;
  inherited;
end;

procedure TSceneGUIList.Render;
var
rescliprect:TRect;
i:integer;
ExSize:real;
letterheight:real;
Colored:TColor4;
begin
  if not Visible then
  exit;
  rescliprect:=Canvas.ClipRect;
  Canvas.ClipRect:=Bounds(Left,Top,Width,Height);
  ExSize:=Fonts[FontNumb].Scale;
  Fonts[FontNumb].Scale:=FontScale;
  if not Enabled then
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,DisabledColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontDisabledColor[0],
      FontDisabledColor[1], FontRenderFX);
  end
  else
  begin
    Canvas.Rectangle(Left,Top,Width,Height,LineColor,EnabledColor,RenderFX);
    Fonts[FontNumb].TextOut(Caption,
      Left+Width/2-Fonts[FontNumb].TextWidth(Caption)/2,
      Top+Height/2-Fonts[FontNumb].TextHeight(Caption)/2,FontEnabledColor[0],
      FontEnabledColor[1], FontRenderFX);
  end;
  letterheight:=Fonts[FontNumb].TextHeight('1');
  for i := 0 to Strings.Count-1 do
  begin
    if SelectedNumb=i then
    Colored:=PushedColor
    else
    if RolledoverNumb=i then
    Colored:=HighlightedColor
    else
    Colored:=EnabledColor;
    Canvas.Rectangle(Left+5,-ScrollY+round(Top+5+i*(5+letterheight)),Width-10,
      round(letterheight+1), LineColor,Colored,RenderFX);
    Fonts[FontNumb].TextOut(Strings[i],
      Left+Width/2-Fonts[FontNumb].TextWidth(Strings[i])/2,
      -ScrollY+round(Top+5+i*(5+letterheight)),FontEnabledColor[0],
      FontEnabledColor[1], FontRenderFX);
  end;
  Fonts[FontNumb].Scale:=ExSize;
  Canvas.ClipRect:=rescliprect;
  if Strings.Count*(5+letterheight)>Height then
  begin
    Canvas.FrameRect(Bounds(Left+Width+1,Top,14,
      Height), LineColor, RenderFX);
    Canvas.Rectangle(Left+Width+2,
      Top+1+round(ScrollY*Height/(5+Strings.Count*(5+letterheight))),12,
      round(Height*Height/(5+Strings.Count*(5+letterheight))-2), LineColor,
      EnabledColor,RenderFX);
  end;
  if Visible then
  for i := 0 to ControlsCount-1 do
  FControls[i].Render;
end;

constructor TSceneGUIList.Create(AImages: TAsphyreImages; ACanvas: TAsphyreCanvas;
  AFonts: TAsphyreFonts; AKeyboard: TAsphyreKeyboard; AMouses: TAsphyreMouse;
  Bounds:TRect);
begin
  inherited;
  Strings:=TStringList.Create;
  SelectedNumb:=-1;
  RolledoverNumb:=-1;
  PushedNumb:=-1;
end;

procedure TSceneGUIMultiEdit.Move;
begin
  inherited;
  if Mouses.Pressed[0] then
  begin
    if AllHeight>Height then
    if PtInRect(Bounds(Left+Width+1,Top,14,Height),Mouse.CursorPos) then
    begin
//      ScrollY:=round((Mouse.CursorPos.Y-Top-
//        round(Height*Height/(5+)/2)/Height*(5+
//        Strings.Count*(5+letterheight)));
//      ScrollY:=Max(ScrollY,0);
//      ScrollY:=Min(ScrollY,round((5+Strings.Count*(5+
//        letterheight))-Height));
    end;
  end;
end;

procedure TSceneGUIMultiEdit.Render;
var
rescliprect:TRect;
letterwidth,letterheight,spacedwidth:real;
FontColor1,FontColor2:cardinal;
i:integer;
begin
  if not Visible then
  exit;
  rescliprect:=Canvas.ClipRect;
  Canvas.ClipRect:=Bounds(Left,Top,Width,Height);

  if not Enabled then
  Canvas.Rectangle(Left,Top,Width,Height,LineColor,DisabledColor,RenderFX)
  else
  if Pressed then
  Canvas.Rectangle(Left,Top,Width,Height,LineColor,PushedColor,RenderFX)
  else
  if MouseIsIn then
  Canvas.Rectangle(Left,Top,Width,Height,LineColor,HighlightedColor,RenderFX)
  else
  Canvas.Rectangle(Left,Top,Width,Height,LineColor,EnabledColor,RenderFX);

  if Pressed then
  begin
    FontColor1:=FontPushedColor[0];
    FontColor2:=FontPushedColor[1];
  end
  else
  if MouseIsIn then
  begin
    FontColor1:=FontHighlightedColor[0];
    FontColor2:=FontHighlightedColor[1];
  end
  else
  if Enabled then
  begin
    FontColor1:=FontEnabledColor[0];
    FontColor2:=FontEnabledColor[1];
  end
  else
  begin
    FontColor1:=FontDisabledColor[0];
    FontColor2:=FontDisabledColor[1];
  end;

  AllHeight:=TextLines(Caption,Left+5,Top+5,1,0,FontColor1,FontColor2,
    width-10,FontRenderFX,Top,Top+Height);

  if Visible then
  for i := 0 to ControlsCount-1 do
  FControls[i].Render;
  Canvas.ClipRect:=rescliprect;

  if Caption='' then
  exit;
  if not Selected then
  exit;

{  letterwidth:=Fonts[FontNumb].TextWidth(Caption[Position+1])*FontScale;
  Canvas.Rectangle(
    round(left+width/2-Fonts[FontNumb].TextWidth(Caption)*FontScale/2+
    spacedwidth),round(Top+Height/2-letterheight/2),
    round(letterwidth),round(letterheight),LineColor,HighlightedColor,
    RenderFX);}

end;

end.

